<!-- eslint-disable max-len -->
<template>
  <a-spin :spinning="spinning">
    <a-form-model
      ref="ruleForm"
      :model="form"
      :label-col="labelCol"
      :wrapper-col="wrapperCol"
      class="dynamicForm"
    >
      <template v-for="(option, optionIdx) in formOptions">
        <template
          v-if="Object.keys(option).length && !option.isTable && !option.isHide"
        >
          <a-row :key="`${option.inputName}row${optionIdx}`">
            <h2>
              {{ option.title }}
              <a-button
                type="link"
                icon="minus-circle"
                v-if="
                  option.isAddable &&
                    formOptions.filter(
                      (opt) => opt.inputName === option.inputName,
                    ).length > 1
                "
                @click="
                  remove(
                    formOptions,
                    optionIdx,
                    `${option.inputName}_${optionIdx}`,
                  )
                "
              >
              </a-button>
            </h2>
            <template v-for="(row, rowIdx) in option.rows">
              <a-row
                :key="`${option.inputName}${row.inputName}`"
                v-if="Object.keys(row).length"
                type="flex"
              >
                <template v-for="(item, itemIdx) in row.children">
                  <a-col
                    span="24"
                    v-if="item.type === 'title'"
                    :key="`${optionIdx}_${rowIdx}_${itemIdx}`"
                  >
                    <h3>
                      {{ item.label }}
                    </h3>
                  </a-col>
                  <template v-else>
                    <a-col
                      :key="`${optionIdx}_${rowIdx}_${itemIdx}`"
                      :span="item.span || 8"
                      v-show="
                        !item.isHide &&
                          form[
                            `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                          ] !== 'N/A'
                      "
                    >
                      <a-form-model-item
                        :label="item.label || ''"
                        :prop="
                          `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                        "
                        :labelCol="item.span ? { span: 4 } : null"
                        :wrapperCol="item.span ? { span: 20 } : null"
                        :rules="(formType === FORMTYPE.ADD || formType === FORMTYPE.EDIT) ? item.rules : [] || []"
                        :title="titleFormat(item, form[`${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`])"
                      >
                        <a-input
                          v-if="item.type === 'input'"
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          :placeholder="item.placeholder || '请填写'"
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          @change="
                            handleValueChange(
                              $event.target.value,
                              option,
                              row,
                              item,
                              optionIdx,
                              rowIdx,
                            )
                          "
                        />
                        <a-input-search
                          v-if="item.type === 'search'"
                          enter-button
                          @search="onSearch"
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          :placeholder="item.placeholder || '请填写'"
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          @change="
                            handleValueChange(
                              $event.target.value,
                              option,
                              row,
                              item,
                              optionIdx,
                              rowIdx,
                            )
                          "
                        />
                        <a-input-search
                          v-if="item.type === 'sync'"
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          :placeholder="item.placeholder || '请填写'"
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          @change="
                            handleValueChange(
                              $event.target.value,
                              option,
                              row,
                              item,
                              optionIdx,
                              rowIdx,
                            )
                          "
                        >
                          <a-button
                            slot="enterButton"
                            icon="sync"
                            :disabled="item.disabled || false || isCheck"
                            @click.native="
                              onSync(option, item, optionIdx, rowIdx)
                            "
                            title="点击后弹窗展示数据"
                          >
                          </a-button>
                        </a-input-search>
                        <a-input-search
                          v-if="item.type === 'calculate'"
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          :placeholder="item.placeholder || '请填写'"
                          :title="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                        >
                          <a-button
                            slot="enterButton"
                            icon="calculator"
                            :disabled="isCheck"
                            @click.native="
                              onCalculate(item)
                            "
                            title="点击后计算费用"
                          >
                          </a-button>
                        </a-input-search>
                        <a-textarea
                          v-if="item.type === 'textarea'"
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          :placeholder="item.placeholder || '请填写'"
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          :auto-size="{ minRows: 2, maxRows: 6 }"
                        />
                        <div v-else-if="item.type === 'select' && item.isPopup">
                          <a-select
                            class="selectPopup"
                            :allowClear="item.allowClear || false"
                            :disabled="item.disabled || false || isCheck"
                            :options="item.options || []"
                            :placeholder="item.placeholder || '请选择'"
                            v-model="
                              form[
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                              ]
                            "
                            @change="
                              handleValueChange(
                                $event,
                                option,
                                row,
                                item,
                                optionIdx,
                                rowIdx,
                              )
                            "
                            @focus="
                              handleItemFocus(
                                item,
                                option,
                                `${option.inputName}_${optionIdx}`,
                              )
                            "
                          />
                          <a-button
                            :disabled="item.disabled || false || isCheck"
                            type="primary"
                            icon="file-sync"
                            title="弹窗展示关联数据"
                            @click="
                              handleSelectPopup(
                                item,
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`,
                              )
                            "
                          />
                        </div>
                        <a-select
                          v-else-if="
                            item.type === 'select' && !item.isCustomize
                          "
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          :options="item.options || []"
                          :placeholder="item.placeholder || '请选择'"
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          @change="
                            handleValueChange(
                              $event,
                              option,
                              row,
                              item,
                              optionIdx,
                              rowIdx,
                            )
                          "
                          @focus="
                            handleItemFocus(
                              item,
                              option,
                              `${option.inputName}_${optionIdx}`,
                            )
                          "
                        />
                        <a-select
                          v-if="item.type === 'select' && item.isCustomize"
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          :placeholder="item.placeholder || '请选择'"
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          :options="item.options || []"
                          @change="
                            handleValueChange(
                              $event,
                              option,
                              row,
                              item,
                              optionIdx,
                              rowIdx,
                            )
                          "
                          @focus="
                            handleItemFocus(
                              item,
                              option,
                              `${option.inputName}_${optionIdx}`,
                            )
                          "
                        >
                          <div slot="dropdownRender" slot-scope="menu">
                            <v-nodes :vnodes="menu" />
                            <a-divider style="margin: 4px 0" />
                            <div
                              style="padding: 4px 8px; cursor: pointer"
                              @mousedown="(e) => e.preventDefault()"
                              @click="addSelectOption(item)"
                            >
                              <a-icon type="plus" /> 自定义
                            </div>
                          </div>
                        </a-select>
                        <a-cascader
                          v-if="item.type === 'cascader'"
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          :options="areaData"
                          :expandTrigger="'hover'"
                          :placeholder="item.placeholder || '请选择'"
                        />
                        <a-date-picker
                          v-if="item.type === 'datepicker'"
                          :allowClear="item.allowClear || false"
                          :disabled="item.disabled || false || isCheck"
                          :showTime="item.showTime || false"
                          :value-format="item.valueFormat || 'YYYY-MM-DD'"
                          :format="item.valueFormat || 'YYYY-MM-DD'"
                          v-model="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          @change="
                            handleValueChange(
                              $event,
                              option,
                              row,
                              item,
                              optionIdx,
                              rowIdx,
                            )
                          "
                          style="min-width: auto; width: 100%"
                        />
                        <div
                          v-if="item.type === 'autoComplete'"
                          style="display: flex; flex-warp: nowrap"
                        >
                          <a-auto-complete
                            :allowClear="item.allowClear || false"
                            :disabled="item.disabled || false || isCheck"
                            v-model="
                              form[
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                              ]
                            "
                            :dataSource="item.options"
                          ></a-auto-complete>
                          <a-button
                            type="primary"
                            icon="search"
                            v-if="item.isNav"
                            @click="
                              handleNavTo(
                                option,
                                row,
                                item,
                                `${option.inputName}_${optionIdx}_${rowIdx}`,
                              )
                            "
                            :disabled="isCheck"
                          />
                        </div>
                        <a-upload
                          v-if="item.type === 'upload'"
                          :action="item.action | urlFilter"
                          :headers="headerFormat"
                          :before-upload="
                            (file, fileList) => {
                              return beforeUpload(
                                file,
                                item,
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`,
                              );
                            }
                          "
                          :showUploadList="false"
                          :fileList="
                            form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]
                          "
                          @change="
                            handleUploadChange(
                              $event,
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`,
                            )
                          "
                          :disabled="loading || isCheck || item.disabled"
                        >
                          <a-button :loading="loading">
                            <a-icon type="upload" v-if="!loading" />
                            上传文件
                          </a-button>
                        </a-upload>
                        <ul
                          class="fileList"
                          v-if="
                            item.type === 'upload' &&
                              form[
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                              ] !== ''
                          "
                        >
                          <li
                            v-for="(file, fileIdx) in form[
                              `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                            ]"
                            :key="`${file.name}${fileIdx}`"
                          >
                            <a-icon
                              class="icon"
                              type="cloud-download"
                              @click="downloadFile(file)"
                            />
                            <span @click="downloadFile(file)">{{
                              file.name
                            }}</span>
                            <a-icon
                              class="icon"
                              type="close-circle"
                              @click="
                                removeUploadFile(
                                  `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`,
                                  fileIdx,
                                )
                              "
                              v-if="!(isCheck || item.disabled)"
                            />
                          </li>
                        </ul>
                        <span v-if="item.remark && !form[`${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`]">{{item.remark}}</span>
                      </a-form-model-item>
                    </a-col>
                  </template>
                </template>
                <a-col span="24">
                  <a-button
                    type="link"
                    icon="minus-circle"
                    v-if="
                      row.isAddable &&
                        option.rows.filter((r) => r.inputName === row.inputName)
                          .length > 1
                    "
                    @click="
                      remove(
                        option.rows,
                        rowIdx,
                        `${option.inputName}_${optionIdx}_${rowIdx}`,
                      )
                    "
                  />
                </a-col>
                <a-col
                  span="24"
                  v-if="
                    row.isAddable &&
                      row ===
                        option.rows
                          .filter((r) => r.inputName === row.inputName)
                          .at(-1)
                  "
                  style="text-align: center"
                >
                  <a-button
                    icon="plus"
                    type="primary"
                    @click="add(option.rows, row, rowIdx)"
                    v-if="!isCheck"
                    >新增行</a-button
                  >
                </a-col>
              </a-row>
            </template>
          </a-row>
          <a-button
            :key="`button${optionIdx}`"
            type="primary"
            icon="plus"
            block
            style="margin-top: 1rem"
            v-if="
              option.isAddable &&
                option ===
                  formOptions
                    .filter((opt) => opt.inputName === option.inputName)
                    .at(-1) &&
                !isCheck
            "
            @click="add(formOptions, option, optionIdx, 'option')"
          >
            新增选项卡
          </a-button>
        </template>
        <template v-else-if="option.isTable">
          <h2 :key="`${option.inputName}_table_title_${optionIdx}`">
            {{ option.title }}
          </h2>
          <div :key="`${option.inputName}_table_operate_${optionIdx}`" v-if="!isCheck">
            <a-button icon="plus" type="default" @click="add(option.rows, option.rows[0], option.rows.length, 'row', `${option.inputName}_${optionIdx}`)" v-if="option.isNew">新增</a-button>
            <span v-if="option.syncData">
              <a-divider type="vertical"></a-divider>
              <a-button type="primary">获取</a-button>
            </span>
          </div>
          <div :key="`${option.inputName}_table_operate_${optionIdx}`" v-else>
            <a-button v-if="option.isExport" @click="handleExport(option, optionIdx)">导出</a-button>
          </div>
          <div :key="`${option.inputName}_table_list_${optionIdx}`" style="overflow: auto">
            <table :key="`${option.inputName}_table_table_${optionIdx}`" class="table" :id="option.inputName">
              <thead>
                <tr>
                  <template v-for="item in option.rows[0].children">
                    <th v-if="!item.isHide" :key="`${option.inputName}_th_${item.inputName}`">
                      {{ item.label }}
                    </th>
                  </template>
                  <th v-if="option.isRemove && formType !== FORMTYPE.CHECK">
                    操作
                  </th>
                </tr>
              </thead>
              <tbody>
                <template
                  v-for="(row, rowIdx) in option.rows.slice(
                    1,
                    option.rows.length,
                  )"
                >
                  <tr
                    :key="`table_${rowIdx}_${row.inputName}`"
                    v-if="row && Object.keys(row).length"
                  >
                    <template v-for="(item, idx) in row.children">
                      <td v-if="!item.isHide" :key="`${item.inputName}_${idx}`">
                        <a-form-model-item
                          :prop="
                            `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                          "
                          :rules="item.rules || []"
                          v-if="!item.disabled"
                          :wrapperCol="{ span: 24 }"
                          style="margin:0"
                          :title="titleFormat(item, form[`${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`])"
                        >
                          <a-input
                            v-if="item.type === 'input'"
                            :allowClear="item.allowClear || false"
                            :disabled="item.disabled || false || isCheck"
                            :placeholder="item.placeholder || '请填写'"
                            v-model="
                              form[
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                              ]
                            "
                            @change="
                              handleValueChange(
                                $event.target.value,
                                option,
                                row,
                                item,
                                optionIdx,
                                rowIdx,
                              )
                            "
                          />
                          <a-select
                            v-else-if="item.type === 'select'"
                            :allowClear="item.allowClear || false"
                            :disabled="item.disabled || false || isCheck"
                            :options="item.options || []"
                            :placeholder="item.placeholder || '请选择'"
                            v-model="
                              form[
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                              ]
                            "
                            @change="
                              handleValueChange(
                                $event,
                                option,
                                row,
                                item,
                                optionIdx,
                                rowIdx,
                              )
                            "
                          />
                          <a-input-search
                            @search="onSearch"
                            enter-button
                            v-else-if="item.type === 'search'"
                            :allowClear="item.allowClear || false"
                            :disabled="item.disabled || false || isCheck"
                            :placeholder="item.placeholder || '请填写'"
                            v-model="
                              form[
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                              ]
                            "
                            @change="
                              handleValueChange(
                                $event.target.value,
                                option,
                                row,
                                item,
                                optionIdx,
                                rowIdx,
                              )
                            "
                          />
                          <a-date-picker
                            v-if="item.type === 'datepicker'"
                            :allowClear="item.allowClear || false"
                            :disabled="item.disabled || false || isCheck"
                            :showTime="item.showTime || false"
                            :value-format="item.valueFormat || 'YYYY-MM-DD'"
                            :format="item.valueFormat || 'YYYY-MM-DD'"
                            v-model="
                              form[
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                              ]
                            "
                            style="min-width: auto; width: 100%"
                          />
                        </a-form-model-item>
                        <span
                          v-else
                          :title="titleFormat(item, form[`${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`])"
                          v-valToDictName="{
                            type: item.type,
                            dictionaryType: item.dictionaryType,
                            herfUrl: item.herfUrl,
                            aliasName: item.aliasName,
                            value:
                              form[
                                `${option.inputName}_${optionIdx}_${rowIdx}_${item.inputName}`
                              ],
                          }"
                        >
                        </span>
                      </td>
                    </template>
                    <td v-if="option.isRemove && formType !== FORMTYPE.CHECK">
                      <a-button
                        type="link"
                        @click="
                          remove(
                            option.rows,
                            rowIdx + 1,
                            `${option.inputName}_${optionIdx}_${rowIdx}`,
                            option,
                          )
                        "
                        >删除</a-button
                      >
                    </td>
                  </tr>
                </template>
              </tbody>
            </table>
          </div>
        </template>
        <a-divider
          :key="`divider${optionIdx}`"
          v-if="
            Object.keys(option).length &&
              optionIdx !== formOptions.length - 1 &&
              !option.isHide
          "
        ></a-divider>
      </template>
    </a-form-model>
    <productModal ref="productModal" @selectData="setDataByAliasNameOption" />
    <customModal ref="customModal" />
    <popupModal ref="popupModal" @selectPopupData="setPopupData" />
  </a-spin>
</template>

<script>
import { mapGetters } from 'vuex';
import _ from 'lodash';
import moment from 'moment';
import globalFunctions from './globalFunctions';
import { DATA_CODE_SUCCESS, FORMTYPE } from '@/utils/consts';
import { request, METHOD, getAuthorizationHeader } from '@/utils/request';
import { exportArrayToExcel } from '@/utils/util';
import { genUrlByName } from '@/services/formService';
import productModal from './product-modal.vue';
import customModal from './custom-modal.vue';
import popupModal from './popup-modal.vue';
const API_BASE_URL = require('@/services/baseUrl')
const fileAccept = {
  basicType: ['jpg', 'png', 'jpeg', 'xls', 'xlsx', 'doc', 'docx', 'txt', 'ppt', 'pptx', 'pdf'],
  imageType: ['jpg', 'png', 'jpeg'],
  fileType: ['xls', 'xlsx', 'doc', 'docx', 'txt', 'ppt', 'pptx', 'pdf']
};

export default {
  props: ['formOptions', 'formDeal', 'formType', 'config'],
  name: 'formGroup',
  data() {
    return {
      FORMTYPE,
      form: {},
      labelCol: { span: 8 },
      wrapperCol: { span: 16 },
      loading: false,
      spinning: false,
      params: {}
    };
  },
  computed: {
    ...mapGetters('account', ['areaData', 'dictConfig']),
    headerFormat() {
      return getAuthorizationHeader();
    },
    isCheck() {
      return this.formType === FORMTYPE.CHECK;
    }
  },
  filters: {
    urlFilter(val) {
      return `${API_BASE_URL}${val}`;
    }
  },
  components: {
    productModal,
    customModal,
    popupModal,
    VNodes: {
      functional: true,
      render: (h, ctx) => ctx.props.vnodes
    }
  },
  methods: {
    beforeUpload(file, item, uploadKey) {
      return new Promise((resolve, reject) => {
        let fileTypeValid = true;
        let fileSizeValid = true;
        let fileCountValid = true;
        if (file.size) {
          fileSizeValid = file.size < (item.size || 5) * 1024 * 1024;
        }
        // eslint-disable-next-line max-len
        fileCountValid = this.form[uploadKey] === '' || this.form[uploadKey] === undefined || (this.form[uploadKey] && this.form[uploadKey].length < 18);
        const suffix = file.name.match(/[^\\.]\w*$/)[0];
        if (item.fileType) {
          const fileAcceptList = fileAccept[item.fileType];
          fileTypeValid = fileAcceptList.indexOf(suffix) !== -1;
        }
        if (!fileTypeValid) {
          this.$message.error('文件格式不支持!');
        } else if (!fileSizeValid) {
          this.$message.error(`文件大小不能超过${item.size || 5}MB!`);
        } else if (!fileCountValid) {
          this.$message.error('文件数量不能超过18个!');
        }
        if (fileTypeValid && fileSizeValid && fileCountValid) {
          resolve();
        } else {
          reject();
        }
      });
    },
    handleUploadChange(info, key) {
      if (!(this.form[key])) {
        this.$set(this.form, key, []);
      }
      this.form[key] = info.fileList;
      if (info.file.status === 'uploading') {
        this.loading = true;
        return;
      }
      if (info.file.status === 'done') {
        this.loading = false;
        const fileArray = info.fileList.map((fileData) => (fileData.response ? {
          name: fileData.response.data.name,
          url: fileData.response.data.url,
          objectName: fileData.response.data.objectName
        } : fileData));
        this.form[key] = fileArray;
        if (info.file.response.code === DATA_CODE_SUCCESS) {
          this.$message.info('文件上传成功!');
        } else {
          this.$message.error(info.file.response.message);
        }
      }
    },
    // eslint-disable-next-line function-paren-newline
    handleValueChange: _.debounce(async function(
      value,
      option,
      row,
      item,
      optIdx,
      rowIdx
    ) {
      // 处理数据联动
      this.form[`${option.inputName}_${optIdx}_${rowIdx}_${item.inputName}`] = this.form[`${option.inputName}_${optIdx}_${rowIdx}_${item.inputName}`].trim();
      const {
        actionUrl,
        aliasName,
        refParams,
        relParams,
        changeFuncName
      } = item;
      const refParamArr = refParams ? refParams.map((param) => param.key) : [];
      const relParamsArr = relParams ? relParams.map((param) => param.key) : [];
      // 分别处理'行'是否允许新增的控件change逻辑
      if (value) {
        const params = {};
        params[aliasName] = value;
        if (option.isAddable) {
          option.rows.forEach((ro, rIdx) => {
            ro.children.forEach((child) => {
              if (refParamArr.indexOf(child.aliasName) > -1) {
                params[child.aliasName] = this.form[
                  `${option.inputName}_${optIdx}_${rIdx}_${child.inputName}`
                ];
              }
              if (relParamsArr.indexOf(child.aliasName) > -1) {
                this.form[
                  `${option.inputName}_${optIdx}_${rIdx}_${child.inputName}`
                ] = '';
              }
            });
          });
        } else if (option.isTable) {
          row.children.forEach((child) => {
            if (refParamArr.indexOf(child.aliasName) > -1) {
              params[child.aliasName] = this.form[
                `${option.inputName}_${optIdx}_${rowIdx}_${child.inputName}`
              ];
            }
            if (relParamsArr.indexOf(child.aliasName) > -1) {
              this.form[
                `${option.inputName}_${optIdx}_${rowIdx}_${child.inputName}`
              ] = '';
            }
          });
        } else {
          this.formOptions.forEach((opt, oIdx) => {
            if (!opt.isAddable && Object.keys(opt).length) {
              opt.rows.forEach((ro, rIdx) => {
                if (!ro.isAddable && Object.keys(ro).length) {
                  ro.children.forEach((child) => {
                    if (refParamArr.indexOf(child.aliasName) > -1) {
                      params[child.aliasName] = this.form[
                        `${opt.inputName}_${oIdx}_${rIdx}_${child.inputName}`
                      ];
                    }
                    if (relParamsArr.indexOf(child.aliasName) > -1) {
                      this.form[
                        `${opt.inputName}_${oIdx}_${rIdx}_${child.inputName}`
                      ] = '';
                    }
                  });
                }
              });
            }
          });
        }
        if (actionUrl) {
          const paramsClone = { ...this.params, ...params };
          this.spinning = true;
          this.$emit('spinState', this.spinning);
          const data = await this.loadingData(actionUrl, 'get', paramsClone);
          this.spinning = false;
          this.$emit('spinState', this.spinning);
          if (data) {
            if (option.isAddable) {
              this.setDataByAliasNameOption(
                data,
                option,
                item,
                `${option.inputName}_${optIdx}`
              );
            }
            if (option.isTable) {
              this.setDataByAliasNameRow(
                data,
                row,
                item,
                `${option.inputName}_${optIdx}_${rowIdx}`
              );
            }
            if (changeFuncName && globalFunctions[changeFuncName]) {
              globalFunctions[changeFuncName]({
                formOptions: this.formOptions,
                data,
                funcName: changeFuncName,
                vueComponent: this,
                option,
                optIdx,
                row,
                rowIdx,
                item,
                key: `${option.inputName}_${optIdx}_${rowIdx}`,
                value: this.form[
                  `${option.inputName}_${optIdx}_${rowIdx}_${item.inputName}`
                ]
              });
            }
            this.setDataByAliasNameForm(data, item);
          }
        } else if (changeFuncName) {
          globalFunctions[changeFuncName]({
            formOptions: this.formOptions,
            changeFuncName,
            vueComponent: this,
            option,
            optIdx,
            rowIdx,
            item,
            key: `${option.inputName}_${optIdx}_${rowIdx}`,
            value: this.form[
              `${option.inputName}_${optIdx}_${rowIdx}_${item.inputName}`
            ]
          });
        }
      }
    }, 1000),
    async handleItemFocus(item, option, key) {
      // 点击控件获取数据源
      const { dataUrl, dataParams } = item;
      const params = dataParams.map((param) => param.key);
      if (dataUrl) {
        const param = {};
        option.rows.forEach((row, rowIdx) => {
          if (row.children) {
            row.children.forEach((li) => {
              if (params.indexOf(li.aliasName) > -1) {
                param[li.aliasName] = this.form[`${key}_${rowIdx}_${li.inputName}`] || '';
              }
            });
          }
        });
        const data = await this.loadingData(dataUrl, 'get', param);
        if (JSON.stringify(data) !== JSON.stringify(item.options)) {
          this.$set(item, 'options', data);
        }
      }
    },
    async loadingData(url, method, params) {
      // this.spinning = true;
      try {
        const response = await request(
          API_BASE_URL + url,
          method.toLowerCase() === 'get' ? METHOD.GET : METHOD.POST,
          params
        );
        if (response.data.code !== DATA_CODE_SUCCESS && response.data.message) {
          this.$message.error(response.data.message);
        }
        return response.data.code === DATA_CODE_SUCCESS
          ? response.data.data
          : null;
      } catch (ex) {
        return null;
      } finally {
        // this.spinning = false;
      }
    },
    handleNavTo(option, row, item, key) {
      const { relParams, dataParams } = item;
      const dataParam = dataParams.map((param) => param.key);
      const aliasList = relParams.map((param) => param.key);
      const columns = row.children
        .filter((child) => child.type === 'input' && aliasList.indexOf(child.aliasName) > -1)
        .map((col) => ({
          title: col.label,
          dataIndex: col.aliasName
        }));
      const params = this.generateParams(dataParam);
      params[item.aliasName] = this.form[`${key}_${item.inputName}`];
      this.$refs.productModal.show(columns, {
        option,
        item,
        key,
        params
      });
    },
    addSelectOption(item) {
      const h = this.$createElement;
      let inputValue = '';
      this.$confirm({
        content: h('a-row', {}, [
          h('a-col', { props: { span: 8 } }, '自定义下拉项'),
          h('a-col', { props: { span: 16 } }, [
            h(
              'a-input',
              {
                on: {
                  change: (event) => {
                    inputValue = event.target.value;
                  }
                }
              },
              ''
            )
          ])
        ]),
        onOk: () => {
          if (!item.options) {
            this.$set(item, 'options', []);
          }
          item.options.push({
            title: inputValue,
            value: inputValue
          });
        },
        title: '添加自定义下拉项',
        okText: '确定',
        cancelText: '取消'
      });
    },
    setDataByAliasNameForm(data, item) {
      const { relParams } = item;
      const formData = {};
      const params = relParams.map((p) => p.key);
      this.formOptions.forEach((option, optIdx) => {
        if (
          !option.isTable && !option.isAddable && Object.keys(option).length) {
          option.rows.forEach((row, rowIdx) => {
            if (!row.isAddable && Object.keys(row).length) {
              row.children.forEach((child) => {
                if (params.indexOf(child.aliasName) > -1) {
                  if (typeof data === 'string') {
                    formData[
                      `${option.inputName}_${optIdx}_${rowIdx}_${child.inputName}`
                    ] = data;
                  } else if (child.type === 'select' && !child.dictionaryType) {
                    // eslint-disable-next-line no-param-reassign
                    child.options = data[child.aliasName];
                  } else {
                    formData[
                      `${option.inputName}_${optIdx}_${rowIdx}_${child.inputName}`
                    ] = data[child.aliasName];
                  }
                }
              });
            }
          });
        }
      });
      this.setForm({ data: formData });
    },
    handleSelectPopup(item, formKey) {
      // eslint-disable-next-line max-len
      const { option, key } = globalFunctions.findOptionByAliasName({
        formOptions: this.formOptions,
        aliasName: globalFunctions.funcNameMapAlias[item.changeFuncName]
      });
      let columns = [];
      const selectedKeys = [];
      option.rows.forEach((row, rowIdx) => {
        if (rowIdx === 0) {
          columns = row.children.map((li) => ({
            title: li.label,
            dataIndex: li.aliasName,
            width: 150
          }));
        } else if (row.children) {
          row.children.forEach((li) => {
            if (li.aliasName === 'itemId') {
              selectedKeys.push(
                this.form[`${key}_${rowIdx - 1}_${li.inputName}`]
              );
            }
          });
        }
      });
      if (this.form[formKey]) {
        // eslint-disable-next-line max-len
        this.$refs.popupModal.show(
          columns,
          selectedKeys,
          item.actionUrl,
          { [item.aliasName]: this.form[formKey] },
          item
        );
      } else {
        this.$message.error(`请选择${item.label}`);
      }
    },
    setPopupData(data, item) {
      globalFunctions[
        item.changeFuncName
      ]({
        formOptions: this.formOptions,
        data,
        funcName: item.changeFuncName,
        vueComponent: this
      });
    },
    setDataByAliasNameOption(data, option, item, key) {
      const { relParams } = item;
      const formData = {};
      const params = relParams.map((p) => p.key);
      option.rows.forEach((row) => {
        row.children.forEach((child) => {
          if (params.indexOf(child.aliasName) > -1) {
            if (typeof data === 'string') {
              formData[`${key}_${child.inputName}`] = data;
            } else if (child.type === 'select') {
              const flag = data[child.aliasName].find(
                (li) => li.value === 'custom'
              );
              if (flag) {
                this.$set(child, 'isCustomize', true);
                this.$set(
                  child,
                  'options',
                  data[child.aliasName].filter((li) => li.value !== 'custom')
                );
              } else {
                this.$set(child, 'isCustomize', false);
                this.$set(child, 'options', data[child.aliasName]);
              }
              if (data[child.aliasName].length === 1) {
                formData[`${key}_${child.inputName}`] = data[child.aliasName][0].value;
              }
            } else {
              formData[`${key}_${child.inputName}`] = data[child.aliasName];
            }
          }
        });
      });
      this.setForm({ data: formData });
    },
    setDataByAliasNameRow(data, row, item, key) {
      const { relParams } = item;
      const formData = {};
      const params = relParams.map((p) => p.key);
      row.children.forEach((child) => {
        if (params.indexOf(child.aliasName) > -1) {
          if (typeof data === 'string') {
            formData[`${key}_${child.inputName}`] = data;
          } else if (child.type === 'select') {
            // eslint-disable-next-line no-param-reassign
            child.options = data[child.aliasName];
          } else {
            formData[`${key}_${child.inputName}`] = data[child.aliasName];
          }
        }
      });
      this.setForm({ data: formData });
    },
    generateParams(params) {
      const paramObj = {};
      this.formOptions.forEach((option, optIdx) => {
        if (!option.isAddable && Object.keys(option).length) {
          option.rows.forEach((row, rowIdx) => {
            if (!row.isAddable && Object.keys(row).length) {
              row.children.forEach((li) => {
                if (params.indexOf(li.aliasName) > -1) {
                  paramObj[li.aliasName] = this.form[
                    `${option.inputName}_${optIdx}_${rowIdx}_${li.inputName}`
                  ];
                }
              });
            }
          });
        }
      });
      return paramObj;
    },
    setForm({ data }) {
      this.combineData(data);
    },
    combineData(data) {
      const combine = { ...this.form, ...data };
      this.$set(this, 'form', combine);
    },
    validateForm() {
      return new Promise((resolve, reject) => {
        this.$refs.ruleForm.validate((valid) => {
          if (valid) {
            // eslint-disable-next-line max-len
            if (this.formDeal.afterList && this.formDeal.afterList.length && this.formType === FORMTYPE.ADD) {
              try {
                this.formDeal.afterList.forEach(async (initObj, idx) => {
                  if (initObj.item.actionUrl) {
                    try {
                      const dataParams = initObj.item.dataParams
                        ? initObj.item.dataParams.map((param) => param.key)
                        : [];
                      const data = await this.loadingData(
                        initObj.item.actionUrl,
                        'get',
                        this.generateParams(dataParams)
                      );
                      if (!data) {
                        throw new Error('break loop!');
                      }
                      if (initObj.item.aliasName === 'workId') {
                        this.$emit('supplement', { codeNo: data });
                      }
                      this.setDataByAliasNameForm(data, initObj.item);
                      if (idx === this.formDeal.afterList.length - 1) {
                        resolve(this.form);
                      }
                    } catch (ex) {
                      throw new Error(ex);
                    }
                  }
                });
              } catch (ex) {
                console.log(ex);
              }
            } else {
              resolve(this.form);
            }
          } else {
            this.$message.error('表单未填写完整!');
            reject(valid);
          }
        });
      });
    },
    onSearch() {
      this.$refs.customModal.show();
    },
    async onSync(option, item, optIdx, rowIdx) {
      const { dataUrl, actionUrl } = item;
      if (dataUrl) {
        const data = await this.loadingData(dataUrl, METHOD.GET, {});
        this.form[
          `${option.inputName}_${optIdx}_${rowIdx}_${item.inputName}`
        ] = data;
        // eslint-disable-next-line max-len
        const actionData = await this.loadingData(actionUrl, METHOD.GET, {
          [item.aliasName]: data
        });
        this.setDataByAliasNameOption(
          actionData,
          option,
          item,
          `${option.inputName}_${optIdx}_${rowIdx}`
        );
      }
    },
    async onCalculate(item) {
      const { dataUrl } = item;
      const data = _.cloneDeep(this.config);
      data.bigInfo = this.form;
      const response = await request(API_BASE_URL + dataUrl, METHOD.POST, data);
      if (response.data.code === DATA_CODE_SUCCESS) {
        this.setForm({ data: response.data.data.bigInfo });
      }
    },
    add(oriArray, oriObj, idx, type, optionKey) {
      if (type === 'option') {
        const form = {};
        Object.keys(this.form).forEach((key) => {
          const strIdx = key.match(/\d/).index;
          const arrIdx = parseInt(key[strIdx], 10);
          if (arrIdx <= idx) {
            form[key] = this.form[key];
          } else {
            form[key.replace(/\d/, arrIdx + 1)] = this.form[key];
          }
        });
        this.$set(this, 'form', form);
      } else {
        const data = {};
        oriObj.children.forEach((item) => {
          data[`${optionKey}_${idx - 1}_${item.inputName}`] = item.defaultValue || '';
        });
        this.setForm({ data });
      }
      this.$emit('add', oriArray, oriObj, idx);
    },
    remove(oriArray, idx, key, option) {
      const newData = {};
      Object.keys(this.form).forEach((formKey) => {
        if (formKey.indexOf(key) === -1) {
          newData[formKey] = this.form[formKey];
        }
      });
      // 特殊处理配件信息列表是否原因件
      if (option && option.aliasName === 'partInfo') {
        let reasonValue;
        oriArray[idx].children.forEach((li) => {
          if (li.aliasName === 'isReasonPart') {
            reasonValue = this.form[`${key}_${li.inputName}`];
          }
        });
        if (reasonValue === '1') {
          oriArray.forEach((r) => {
            if (r.children) {
              r.children.forEach((li) => {
                const orili = li;
                if (li.aliasName === 'isReasonPart') {
                  orili.disabled = false;
                }
              });
            }
          });
        }
      }
      this.$set(this, 'form', newData);
      this.$emit('remove', oriArray, idx);
    },
    removeUploadFile(key, idx) {
      this.form[key].splice(idx, 1);
    },
    async downloadFile(file) {
      const { objectName } = file;
      const response = await genUrlByName({ objectName });
      if (response.data.code === DATA_CODE_SUCCESS) {
        window.open(response.data.data, '_blank');
      }
    },
    async setFormDataByDataParams({ option, item, key }, url) {
      const params = {};
      let { dataParams } = item;
      dataParams = dataParams.map((param) => param.key);
      option.rows.forEach((row) => {
        row.children.forEach((li) => {
          if (dataParams.indexOf(li.aliasName) > -1) {
            params[li.aliasName] = this.form[`${key}_${li.inputName}`];
          }
        });
      });
      return this.loadingData(url, 'get', params);
    },
    initial(data) {
      this.setForm({ data });
      if (this.formType === FORMTYPE.ADD) {
        // 新建工单时，需要根据vin码初始化维修记录
        this.initialFormData();
      } else if (this.formType === FORMTYPE.CHECK || this.formType === FORMTYPE.EDIT) {
        this.initialFormSelect();
      }
    },
    initialFormData() {
      this.formDeal.beforeList.forEach(async (initObj) => {
        if (initObj.item.actionUrl && !initObj.item.isLock) {
          const data = await this.setFormDataByDataParams(
            initObj,
            initObj.item.actionUrl
          );
          if (data) {
            this.setDataByAliasNameForm(data, initObj.item);
          }
        } else if (initObj.item.isLock) {
          this.params[initObj.item.aliasName] = this.form[
            `${initObj.key}_${initObj.item.inputName}`
          ];
          if (initObj.item.changeFuncName) {
            const { item, key } = initObj;
            const { changeFuncName } = item;
            globalFunctions[changeFuncName]({
              formOptions: this.formOptions,
              funcName: changeFuncName,
              params: {
                vin: this.form[`${key}_${item.inputName}`],
                formWorkTypeId: this.config.formWorkTypeId
              },
              vueComponent: this
            });
          }
        }
      });
    },
    initialFormSelect() {
      this.formDeal.selectList.forEach(async (initObj) => {
        if (!this.form[`${initObj.key}_${initObj.item.inputName}`]) {
          return false;
        }
        const data = await this.setFormDataByDataParams(
          initObj,
          initObj.item.dataUrl
        );
        if (data) {
          this.formOptions.forEach((option) => {
            option.rows.forEach((row) => {
              if (row.children) {
                row.children.forEach((item) => {
                  if (item.inputName === initObj.item.inputName) {
                    this.$set(item, 'options', data);
                  }
                });
              }
            });
          });
        }
      });
    },
    // 设置表单全局请求参数
    setParams(params) {
      Object.assign(this.params, params);
    },
    exportArrayFormat(option, optIdx, appendTitle = [], appendData = []) {
      const dataArray = [];
      option.rows.forEach((row, rowIdx) => {
        let itemArray = [];
        if (rowIdx === 0) {
          itemArray = row.children.map((li) => li.label).concat(appendTitle);
        } else if (row.children) {
          itemArray = row.children.map((li) => {
            let value = '';
            if (li.type === 'select') {
              const findResult = li.options
                ? li.options.find((selOpt) => selOpt.value === this.form[`${option.inputName}_${optIdx}_${rowIdx - 1}_${li.inputName}`])
                : null;
              value = findResult ? findResult.title : '';
            } else {
              value = this.form[`${option.inputName}_${optIdx}_${rowIdx - 1}_${li.inputName}`];
            }
            return value;
          }).concat(appendData);
        }
        if (itemArray.length) {
          dataArray.push(itemArray);
        }
      });
      return dataArray;
    },
    exportTable(option, optIdx) {
      const dataArray = this.exportArrayFormat(option, optIdx);
      exportArrayToExcel(dataArray, option.title);
    },
    claimsExportTable(option, optIdx) {
      const extraConfig = [
        { label: '索赔单号', key: 'batwuke' },
        { label: '供应商名称', key: 'mlzzaes' },
        { label: '供应商代码', key: 'anuslrt' }
      ];
      const titleAppend = extraConfig.map((config) => config.label);
      const formKeys = Object.keys(this.form);
      const keys = formKeys.map((formKey) => formKey.split('_').at(-1));
      const dataAppend = [];
      extraConfig.forEach((title) => {
        const idx = keys.indexOf(title.key);
        if (idx > -1) {
          dataAppend.push(this.form[formKeys[idx]]);
        }
      });
      const dataArray = this.exportArrayFormat(option, optIdx, titleAppend, dataAppend);
      exportArrayToExcel(dataArray, option.title);
    },
    handleExport(option, optIdx) {
      // eslint-disable-next-line no-unused-expressions, max-len
      option.exportFunc ? this[option.exportFunc](option, optIdx) : this.exportTable(option, optIdx);
    },
    getTargetValueByAlias(item, option, optionIdx) {
      let { dataParams } = item;
      dataParams = dataParams.map((param) => param.key);
      let targetValue = '';
      option.rows.forEach((row, rowIdx) => {
        row.children.forEach((li) => {
          if (dataParams.indexOf(li.aliasName) > -1) {
            targetValue = this.form[`${option.inputName}_${optionIdx}_${rowIdx}_${li.inputName}`];
          }
        });
      });
      return targetValue;
    },
    disabledDate(val, item, option, optionIdx) {
      if (!item.disableDate) {
        return false;
      }
      const sourceValue = val;
      const targetValue = this.getTargetValueByAlias(item, option, optionIdx);
      if (!sourceValue || !targetValue) {
        return false;
      }
      if (item.disableDate === 'start') {
        return moment(sourceValue) >= moment(targetValue);
      }
      return moment(sourceValue) <= moment(targetValue);
    },
    titleFormat(item, value) {
      let title = '';
      if (item.type === 'input' || item.type === 'textarea') {
        title = value;
      }
      return title;
    }
  }
};
</script>
<style lang="less" scoped>
.dynamicForm {
  /deep/ .ant-form-item label {
    white-space: normal;
  }
  h2 {
    font-weight: bold;
  }
  h3 {
    color: #13c2c2;
    list-style: circle;
    list-style-type: circle;
  }
  h3:before {
    content: '#';
  }
  .selectPopup {
    width: calc(100% - 32px);
  }
  .table {
    width: 100%;
    overflow-x: scroll;
    table-layout: fixed;
    text-align: center;
    border: 1px solid lightgray;
    border-collapse: collapse;
    margin-top: 0.5rem;
    th {
      width: 150px;
      padding: 0.3rem;
      border: 1px solid lightgray;
    }
    td {
      width: 150px;
      padding: 0.3rem;
      border: 1px solid lightgray;
    }
  }
  .fileList {
    list-style-type: none;
    padding: 0;
    li {
      display: flex;
      align-items: center;
      span {
        margin: 0 1rem;
        &:hover {
          cursor: pointer;
          color: #13c2c2;
        }
      }
      .icon {
        &:hover {
          cursor: pointer;
          color: #13c2c2;
        }
      }
    }
  }
}
</style>
